package editorsvg.gui.generico;

import java.util.ArrayList;
import java.util.List;
import javax.swing.JTree;
import javax.swing.tree.TreePath;

/**
 * Buscador bidireccional de nodos de arboles swing.
 * Para poder buscar nodos hacia atras conserva una lista secuencial de todos 
 * los nodos. Esto hace que se haga un recorrido inicial de todo el arbol. Esto
 * descarta su uso para modelos de arbol con muchos nodos (por ejemplo modelos contra
 * la base de datos).
 * 
 * @author Jorge Berjano
 */
public class BuscadorNodoArbolBidireccional {

    private JTree arbol;
    private Comparador comparador;
    private TreePath caminoInicialBusqueda;
    private boolean buscando;
    private List<TreePath> listaCaminos;

    public BuscadorNodoArbolBidireccional(JTree arbol) {
        this.arbol = arbol;
        listaCaminos = new ArrayList<TreePath>();
        agregarCamino(new TreePath(arbol.getModel().getRoot()));
        buscando = true;
    }

    private void agregarCamino(TreePath camino) {
        listaCaminos.add(camino);
        Object padre = camino.getLastPathComponent();
        int numeroHijos = arbol.getModel().getChildCount(padre);
        for (int i = 0; i <
                numeroHijos; i++) {
            Object hijo = arbol.getModel().getChild(padre, i);
            agregarCamino(camino.pathByAddingChild(hijo));
        }
    }

    public TreePath getCaminoInicialBusqueda() {
        return caminoInicialBusqueda;
    }

    public void setCaminoInicialBusqueda(TreePath caminoInicial) {
        this.caminoInicialBusqueda = caminoInicial;
        buscando = false;
    }

    public interface Comparador {

        boolean comparar(Object objetoArbol);
    }

    public class ComparadorObjeto implements Comparador {

        public Object objeto;

        public ComparadorObjeto(Object objeto) {
            this.objeto = objeto;
        }

        public boolean comparar(Object objetoArbol) {
            return objetoArbol.equals(objeto);
        }
    }

    public class ComparadorContieneTexto implements Comparador {

        public String texto;

        public ComparadorContieneTexto(String texto) {
            this.texto = texto.toLowerCase();
        }

        public boolean comparar(Object objetoArbol) {
            String textoObjetoArbol = objetoArbol.toString().toLowerCase();
            return textoObjetoArbol.indexOf(texto) >= 0;
        }
    }

    public TreePath buscar(Comparador comparador, boolean atras) {
        this.comparador = comparador;
        return realizarBusqueda(atras);
    }

    public TreePath buscarNodo(Object nodo, boolean atras) {
        comparador = new ComparadorObjeto(nodo);

        return realizarBusqueda(atras);
    }

    public TreePath buscarTexto(String texto, boolean atras) {
        comparador = new ComparadorContieneTexto(texto);

        return realizarBusqueda(atras);
    }

    private TreePath realizarBusqueda(boolean atras) {
        if (atras) {
            return realizarBusquedaAnterior();
        } else {
            return realizarBusquedaSiguiente();
        }
    }

    private TreePath realizarBusquedaSiguiente() {
        for (TreePath camino : listaCaminos) {
            if (compararNodo(camino)) {
                return camino;
            }
        }
        return null;
    }

    private TreePath realizarBusquedaAnterior() {

        for (int i = listaCaminos.size() - 1; i > 0; i--) {
            TreePath camino = listaCaminos.get(i);
            if (compararNodo(camino)) {
                return camino;
            }
        }
        return null;
    }

    private boolean compararNodo(TreePath camino) {
        Object padre = camino.getLastPathComponent();
        if (buscando) {
            if (comparador.comparar(padre)) {
                return true;
            }
        }

        if (camino.equals(getCaminoInicialBusqueda())) {
            buscando = true;
        }
        return false;
    }
//    private TreePath buscarNodo(TreePath camino) {
//        
//        Object padre = camino.getLastPathComponent();
//        if (buscando) {            
//            if (comparador.comparar(padre)) {
//                return camino;
//            }
//        }
//        
//        if (camino.equals(caminoInicialBusqueda)) {
//            buscando = true;
//        }
//
//        int numeroHijos = arbol.getModel().getChildCount(padre);
//        for (int i = 0; i < numeroHijos; i++) {
//            Object hijo = arbol.getModel().getChild(padre, i);
//            TreePath resultado = buscarNodo(camino.pathByAddingChild(hijo));
//            if (resultado != null) {
//                return resultado;
//            }
//        }
//        return null;
//    }
}
